<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class LimitMiddleware
{
	private $_water;    //漏斗的当前水量(也就是请求数)
	private $_burst = 2;    //漏斗总量(超过将直接舍弃)
	private $_rate = 1; //漏斗出水速率(限流速度)
	private $_lastTime; //记录每次请求的时间(因为需要记录每次请求之间的出水量也就是请求数)
	private $_redis;    //redis对象
	
	
	public function __construct()
	{
		$this->_redis = new \Redis();
		$this->_redis->connect('127.0.0.1', 6379);
		$this->_lastTime = time(); //需要记录每次访问的时间
	}
	
	/**
	 * Handle an incoming request.
	 *
	 * @param \Illuminate\Http\Request $request
	 * @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
	 * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
	 */
	public function handle(Request $request, Closure $next)
	{
		$now = time();
		$redisKey = 'leackBucket_api';
		
		if (!empty($time = $this->_redis->get($redisKey))) {
			$this->_lastTime = $time; //获取上一次访问时间
		}
		if (!empty($water = $this->_redis->get('water'))) {
			$this->_water = $water;//获取上次请求后桶剩余水量
		}
		
		//计算这一次访问的时间到上一次访问时间的时间间隔
		//因为rate是固定的，所以可以认为“时间间隔 * rate”即为漏出的水量
		$s = $now - $this->_lastTime; //当前时间减去上次访问时间，得到时间间隔
		$outCount = $s * $this->_rate; //漏出的水量（请求数）
		//执行漏水，计算剩余水量，也就是当前请求
		$this->_water = ($this->_water - $outCount);
		if ($this->_water < 0) {
			$this->_water = 0; //重置为0
		}
		//var_dump($this->_water . '----请求数');
		//请求数超出了突发请求限制
		if ($this->_water > $this->_burst) {
			echo "超出桶限制";
			return false;
		}
		$this->_lastTime = $now; // 更新时间
		$this->_water++;//更新待请求数
		$this->_redis->set($redisKey, $now);
		//记录请求数
		$this->_redis->set('water', $this->_water);
		return $next($request);
	}
}
